#! /usr/bin/env python

import os,sys,fnmatch
import csv,collections
import numpy as np


def scan_file(filename,comment="#"):
    # Read in lines of file and determine character
    # used to to connect parameters to values
    lines = []
    equiv = None
    f = open(filename,"r")
    for line in f:
        if not line.lstrip().startswith(comment):
            if "=" in line:
                equiv = "="
            elif ":" in line:
                equiv = ":"
            else:
                equiv = " "
            iline = line.strip()
            if comment in iline:
                iline = iline.split(comment)[0]
            iline = iline.strip()
            iline = iline.split(equiv)
            dummy = iline.pop(0)
            iline = "".join(iline)
            lines.append(iline.replace("\n","").strip())
    f.close()    
    # Determine vectors information
    vectors = "123"    
    findstart = lambda x,c: [i for i in x if i.strip().startswith(c)]
    findend = lambda x,c: [i for i in x if i.strip().endswith(c)]
    for char in ["[","(","{"]:
        if len(findstart(lines,char)) > 0 and "1" in vectors:
            vectors = vectors.replace("1",char)
    if "1" in vectors:
        vectors = vectors.replace("1"," ")
    for char in ["]",")","}"]:
        if len(findend(lines,char)) > 0 and "3" in vectors:
            vectors = vectors.replace("3",char)
    if "3" in vectors:
        vectors = vectors.replace("3"," ")
    if len(vectors.strip()) == 1:
        line = max(lines,key=len)
    else:
        vectors_lines = findstart(lines,vectors[0])
        vectors_lines = findend(vectors_lines,vectors[2])
        line = max(vectors_lines,key=len)
        if vectors[0] != " ":
            line = line.replace(vectors[0],"")
        if vectors[2] != " ":
            line = line.replace(vectors[2],"")
    delim = None
    line = line.strip()
    for char in [",",";"," / "," "]:
        if char in line:
            delim = char
            break
    if delim is None:
        delim = " "
        #sniffer = csv.Sniffer()
        #delim = sniffer.sniff(line).delimiter    
    vectors = vectors.replace("2",delim)
    # Return formatting information      
    return vectors,equiv
    
    
class parameters(object):
    
    def __init__(self,ref_file=None,comment="#"):        
        # Check parameters file provided
        if ref_file is None:
            print "*** ERROR! parameters.__init__ : no reference parameters file specified!"
            sys.exit(3)
        # Check parameters file exists
        if not os.path.exists(ref_file):
            print "*** ERROR! parameters.__init__ : no reference parameters file specified!"
            sys.exit(3)
        # Scan file to store formatting characters
        self._vectors = "   "
        self._equiv = " "
        self._vectors,self._equiv = scan_file(ref_file,comment=comment)
        # Initialise dictionary to store parameters
        self._params = collections.OrderedDict()        
        # Read file and store parameters
        f = open(ref_file)
        for fline in f:
            line = fline.strip().replace("\n","")
            line = line.strip().replace("\t"," ")            
            if not line.startswith(comment) and len(line)>0:
                # Extract parameter name from start of line
                iend = line.index(" ")
                param = line[:iend]
                line = line.replace(param,"",1).lstrip()
                # Remove equivalency character
                if line.startswith(self._equiv):
                    line = line[1:]                                
                # Remove any comments after parameter value
                if comment in line:
                    line = line.split(comment)[0].strip()
                # Is a vector?
                value = line.strip()
                if np.logical_or(self._vectors[0] in value,self._vectors[1] in value):
                    if value.startswith(self._vectors[0]):
                        value = value[1:].strip()
                    if value.endswith(self._vectors[2]):
                        value = value[:-1]
                    value = value.split(self._vectors[1])
                # Store parameter in dictionary
                self._params[param] = value
        f.close()
        return

    def list(self):
        return self._params.keys()


    def get(self,param=None):
        if param is None:
            return self._params
        if param in self._params.keys():
            return self._params[param]
        else:
            return None

    def remove(self,param):
        if param in self._params.keys():
            del self._params[param]
        return
                    
    def modify(self,value,param=None):        
        # If inputting dictionary or parameters
        if type(value) is dict:
            for p,v in value.items():
                val = v
                if p in self._params.keys():
                    if np.ndim(self._params[p])>0:
                        val = v
                        if np.ndim(v) == 0:
                            val = [v]
                    else:
                        val = v
                        if np.ndim(v) > 0:
                            if self._vectors[0] != " " and self._vectors[2] != " ":
                                val = v[0]
                self._params[p] = val
        else:
            if param is None:        
                print "*** ERROR! parameters.modify : no parameter name specified!"
                print "         [Only leave parameter name blank if type(value) = dict]"
                sys.exit(3)
            if param in self._params.keys():                
                if np.ndim(self._params[param])>0:
                    if np.ndim(value) == 0:
                        value = [value]
                else:
                    if np.ndim(value) > 0:
                        if self._vectors[0] != " " and self._vectors[2] != " ":
                            value = value[0]
            self._params[param] = value
        return

    def output(self,ofile=None):        
        if ofile is not None:
            f = open(ofile,"w")
        for param,value in self._params.items():
            if np.ndim(value) > 0:
                vector = list(self._vectors)
                line = vector[0] + vector[1].join(map(str,list(value))).strip() + vector[2]
            else:
                line = str(value)
            line = param + " " + self._equiv.strip() + " " + line.strip()
            if ofile is None:
                print line
            else:
                f.write(line+"\n")
        if ofile is not None:
            f.close()
            print "PARAMETERS FILE = ",ofile
        return    

        
        
        
